import { createTaskQueue, arrified, createStateNode, getTag } from "../misc"
import { updateNodeElement } from "../misc/dom"

const taskQueue = createTaskQueue()
let subTask

let pendingCommit

const commitAllWork = (fiber) => {
    console.log(fiber)
    fiber.effects.forEach(item => {
        if (item.effectTag === "delete") {
            item.parent.stateNode.removeChild(item.stateNode)
        } else if (item.effectTag === "update") {
            /**
             * 更新
             */
            if (item.type === item.alternate.type) {
                /**
                 *  节点类型相同
                 */
                updateNodeElement(item.stateNode, item, item.alternate)
            } else {
                /**
                 * 节点类型不同
                 */
                item.parent.stateNode.replaceChild(
                    item.stateNode,
                    item.alternate.stateNode
                )
            }
        } else if (item.effectTag === 'placement') {
            let fiber = item
            let parentFiber = fiber.parent
            while (parentFiber.tag === 'class_component' || parentFiber.tag === 'function_component') {
                parentFiber = parentFiber.parent
            }
            if (fiber.tag === 'host_component') {
                parentFiber.stateNode.appendChild(fiber.stateNode)
            }
        }
    })
    /**
     * 备份旧的 fiber 节点对象
     */
    fiber.stateNode.__rootFiberContainer = fiber
}

const getFirstTask = () => {
    const task = taskQueue.pop()
    return {
        props: task.props,
        stateNode: task.dom,
        tag: "host_root",
        effects: [],
        child: null,
        alternate: task.dom.__rootFiberContainer
    }
}

const reconcileChildren = (fiber, children) => {
    const arrifiedChildren = arrified(children)

    let index = 0
    let numberOfElements = arrifiedChildren.length
    let element = null
    let newFiber
    let preFiber
    let alternate

    if (fiber.alternate && fiber.alternate.child) {
        alternate = fiber.alternate.child
    }

    while (index < numberOfElements || alternate) {
        element = arrifiedChildren[index]
        if (!element && alternate) {
            /**
             * 删除操作
             */
            alternate.effectTag = "delete"
            fiber.effects.push(alternate)
        } else if (element && alternate) {
            /**
             * 更新
             */
            newFiber = {
                type: element.type,
                props: element.props,
                tag: getTag(element),
                effects: [],
                effectTag: "update",
                parent: fiber,
                alternate
            }
            if (element.type === alternate.type) {
                /**
                 * 类型相同
                 */
                newFiber.stateNode = alternate.stateNode
            } else {
                /**
                 * 类型不同
                 */
                newFiber.stateNode = createStateNode(newFiber)
            }
        } else if (element && !alternate) {
            /**
             * 初始渲染
             */
            /**
             * 子级 fiber 对象
             */
            newFiber = {
                type: element.type,
                props: element.props,
                tag: getTag(element),
                effects: [],
                effectTag: "placement",
                parent: fiber
            }
            /**
             * 为fiber节点添加DOM对象或组件实例对象
             */
            newFiber.stateNode = createStateNode(newFiber)
        }
        if (index === 0) {
            fiber.child = newFiber
        } else if(element){
            preFiber.sibling = newFiber
        }

        if (alternate && alternate.sibling) {
            alternate = alternate.sibling
        } else {
            alternate = null
        }

        preFiber = newFiber
        index++
    }


}

const executeTask = fiber => {

    if (fiber.tag === 'class_component') {
        reconcileChildren(fiber, fiber.stateNode.render())
    } else if (fiber.tag === 'function_component') {
        reconcileChildren(fiber, fiber.stateNode(fiber.props))
    } else {
        reconcileChildren(fiber, fiber.props.children)
    }

    if (fiber.child) {
        return fiber.child
    }

    let currentExecutelyFiber = fiber
    while (currentExecutelyFiber.parent) {
        currentExecutelyFiber.parent.effects = currentExecutelyFiber.parent.effects.concat(
            currentExecutelyFiber.effects.concat([currentExecutelyFiber])
        )
        if (currentExecutelyFiber.sibling) {
            return currentExecutelyFiber.sibling
        }
        currentExecutelyFiber = currentExecutelyFiber.parent
    }

    pendingCommit = currentExecutelyFiber
}

const workLoop = (deadline) => {
    if (!subTask) {
        subTask = getFirstTask()
    }
    while (subTask && deadline.timeRemaining() > 1) {
        subTask = executeTask(subTask)
    }
    if (pendingCommit) {
        commitAllWork(pendingCommit)
    }
}


const performTask = (deadline) => {

    workLoop(deadline)

    if (subTask || !taskQueue.isEmpty()) {
        requestIdleCallback(performTask)
    }
}

export const render = (element, dom) => {
    taskQueue.push({
        dom,
        props: {
            children: element
        }
    })
    console.log(taskQueue)

    requestIdleCallback(performTask)
}